package club.itstudio.itouc.jw

import club.itstudio.itouc.config.ElectiveCoursecConfig
import club.itstudio.itouc.core.util.CharType
import club.itstudio.itouc.core.util.charType
import club.itstudio.itouc.entity.ElectiveCourse
import club.itstudio.itouc.entity.JwSession
import club.itstudio.itouc.entity.KeyTimeParam
import com.github.kittinunf.fuel.Fuel
import org.springframework.http.HttpHeaders
import org.springframework.http.HttpMethod
import org.springframework.stereotype.Component
import java.io.File

const val JwHost = "http://jwgl.ouc.edu.cn"             // 教务系统主机

const val DataTable = "$JwHost/taglib/DataTable.jsp"    // 数据页

const val Login = "$JwHost/cas/logon.action"            // 登录

const val Captcha = "$JwHost/cas/genValidateCode"       // 验证码

const val OnlineMessage = "$JwHost/online/message"      // 检验会话是否有效的接口

const val DropList = "$JwHost/frame/droplist/getDropLists.action" // 获取专业列表

const val GradeSpecialty = "$JwHost/jw/common/getStuGradeSpeciatyInfo.action" //获取年级专业信息的接口

const val HtmlTimeTable = "$JwHost/student/wsxk.zx.bykb.jsp"        // 二维形式课表接口

const val Coin = "$JwHost/jw/common/getSelectLessonPointsInfo.action"   // 获取学生个人选课币使用情况

const val RepeatCourse = "$JwHost/jw/common/isRepeatCourse.action"      // 学生是否可以重修某一门课的接口

const val SaveCourse = "$JwHost/jw/common/saveElectiveCourse.action" // 选课接口

const val ConfirmCanElective = "$JwHost/jw/common/isSelectableSkbjdm.action" // 选课前检验是否具有资格的接口

const val CancelCourse = "$JwHost/jw/common/cancelElectiveCourse.action" // 删除一门课

const val KeyTimeParam = "$JwHost/custom/js/SetKingoEncypt.jsp"         // 加密参数接口

const val Score = "$JwHost/student/xscj.stuckcj_data.jsp" // 获取成绩接口
/**
 * 教务系统请求参数构建工具
 */
@Component
class ParamsBuilder(val ecConfig: ElectiveCoursecConfig) {

    /**
     * 构造登录参数
     * @param userCode: 学号
     * @param passWord: 密码
     * @param captcha: 验证码
     * @param session: 会话
     */
    fun login(userCode: String, passWord: String, captcha: String, session: JwSession): JwParams{
        // 设置参数 userCode
        val usercode = Encrypt.encodeBase64("$userCode;;${session.jsessionid}")
        // 设置参数 result
        var result = 0
        for (i in passWord.indices) {
            result = result.or(when(passWord[i].charType()) {
                CharType.Digit -> 8
                CharType.Lowercase -> 4
                CharType.Capital -> 2
                CharType.Others -> 1
            })
        }
        // 设置参数 password
        val password = Encrypt.getTripleMD5(passWord, captcha.toLowerCase())

        val params = listOf(
                "_u$captcha" to usercode,
                "_p$captcha" to password,
                "randnumber" to captcha,
                "isPasswordPolicy" to "1",
                "txt_mm_expression" to result.toString(),
                "txt_mm_length" to passWord.length,
                "txt_mm_userzh" to "0"
        )
        return JwParams(Login, HttpMethod.POST, params, charset("utf-8"))
    }

    /**
     * 获取验证码图片
     * @return 验证码图片路径
     */
    fun captcha(jwSession: JwSession): String{
        val prefix = System.currentTimeMillis().toString()
        val suffix = ".jpg"
        var path = ""
        Fuel.download(Captcha)
                .fileDestination{_, _ ->
                    val file = File("captcha/$prefix$suffix")
                    path = file.absolutePath
                    file
                }
                .header(HttpHeaders.COOKIE to jwSession)
                .response()
        return path
    }

    /**
     * 构造检验会话有效性参数
     */
    fun onlineMessage(): JwParams {
        val params = listOf(
                "hidOption" to "getOnlineMessage"
        )
        return JwParams(OnlineMessage, HttpMethod.POST, params)
    }

    /**
     * 构造获取个人的年级、专业信息参数
     */
    fun gradeSpecialtyInfo(): JwParams {
        return JwParams(GradeSpecialty, HttpMethod.POST, charset = charset("utf-8"))
    }

    /**
     * 构造获取某一年份的专业列表的参数
     * @param year: 年份
     */
    fun specialtyList(year: String): JwParams {
        val params = listOf(
                "comboBoxName" to  "MsGrade_Specialty",
                "paramValue" to "nj=$year"
        )
        return JwParams(DropList, HttpMethod.POST, params, charset("utf-8"))
    }

    /**
     * 获取专业课列表
     * @param year: 年份 默认为当前选课时期的年份
     * @param semester: 学期 默认为当前选课时期的学期
     * @param specialty: 所选专业
     * @param grade: 所选年级
     */
    fun specialtyCourseList(grade: String, specialty: String, year: String = ecConfig.year, semester: String = ecConfig.semester)
            = courseList("Specialty", 1, year, semester, grade, specialty)


    /**
     * 获取公共课列表
     * @param page: 页数
     * @param selDepartment: 所选部门
     * @param year: 学年
     * @param semester: 学期
     */
    fun publicClassList(page: Int = 1,
                        selDepartment: String = "",
                        year: String = ecConfig.year,
                        semester: String = ecConfig.semester)
            = courseList("PublicBasic", page, year, semester, selDepartment = selDepartment)

    /**
     * 获取思政课, 0366 社会科学部代码
     */
    fun polityCourseList(page: Int = 1,
                         year: String = ecConfig.year,
                         semester: String = ecConfig.semester)
            = publicClassList(page, "0366", year, semester)

    /**
     * 获取军事概论课, 0358 军事教研室代码
     */
    fun militaryCourseList(page: Int = 1,
            year: String = ecConfig.year,
            semester: String = ecConfig.semester)
            = publicClassList(page, "0358", year, semester)

    /**
     * 获取体育课, 0356 体育系代码
     */
    fun peCourseList(page: Int = 1,
                     year: String = ecConfig.year,
                     semester: String = ecConfig.semester)
    = publicClassList(page, "0356", year, semester)

    /**
     * 获取英语课， 0308 大学外语教学部代码
     */
    fun englishCourseList(page: Int = 1, year: String = ecConfig.year,
                          semester: String = ecConfig.semester)
    = publicClassList(page, "0308", year, semester)

    /**
     * 获取公共物理课
     */
    fun physicsCourseList(page: Int = 1, year: String = ecConfig.year,
                          semester: String = ecConfig.semester)
    = publicClassList(page, "0258", year, semester)

    /**
     * 获取公共化学课
     */
    fun chemistryCourseList(page: Int = 1, year: String = ecConfig.year,
                            semester: String = ecConfig.semester)
    = publicClassList(page, "0267", year, semester)

    /**
     * 获取公共数学课
     */
    fun mathCourseList(page: Int = 1, year: String = ecConfig.year,
                       semester: String = ecConfig.semester)
    = publicClassList(page, "0348", year, semester)

    /**
     * 获取公共计算机基础课
     */
    fun basicComputerCourseList(page: Int = 1, year: String = ecConfig.year,
                                semester: String = ecConfig.semester)
    = publicClassList(page, "0354", year, semester)

    /**
     * 获取通识课
     * @param page: 页数
     * @param year: 学年
     * @param semester: 学期
     */
    fun commonClassList(page: Int = 1,
                        year: String = ecConfig.year,
                        semester: String = ecConfig.semester)
            = courseList("Common",  page,  year, semester)

    /**
     * 获取课程列表
     * @param type: 课程类型
     * @param page: 页数
     * @param year: 学年
     * @param semester: 学期
     * @param selGrade: 所选年级，用于专业课
     * @param selSpecialty: 所选专业，用于专业课
     * @param selDepartment: 所选部门，用于公共课
     */
    private fun courseList(type: String,
                           page: Int = 1,
                           year: String = ecConfig.year,
                           semester: String = ecConfig.semester,
                           selGrade: String = "",
                           selSpecialty: String = "",
                           selDepartment: String = ""): JwParams {
        val params = listOf(
                "xn" to year,
                "xq" to semester,
                "kcfw" to type,
                "tableId" to "6146",
                "sel_zydm" to selSpecialty,
                "sel_nj" to selGrade,
                "currPageCount" to page,
                "sel_cddwdm" to selDepartment)
        return JwParams(DataTable, HttpMethod.POST, params)
    }

    /**
     * 获取学生选课列表
     */
    fun studentCourseList(year: String = ecConfig.year,
                          semester: String = ecConfig.semester,
                          userCode: String): JwParams{
        val params = listOf(
                "xh" to userCode,
                "xn" to year,
                "xq" to semester,
                "tableId" to "6093"
        )
        return JwParams(DataTable, HttpMethod.POST, params)
    }

    /**
     * 获取二维形式的选课表, html格式
     */
    fun htmlTimeTable(userCode: String,
                      year: String = ecConfig.year,
                      semester: String = ecConfig.semester): JwParams {
        val params = listOf(
                "xh" to userCode,
                "xn" to year,
                "xq" to semester
        )
        return JwParams(HtmlTimeTable, HttpMethod.POST, params)
    }

    /**
     * 获取学生选课币使用情况的参数
     */
    fun coinStatus(userCode: String,
                   year: String = ecConfig.year,
                   semester: String = ecConfig.semester): JwParams {
        val params = listOf(
                "xh" to userCode,
                "xn" to year,
                "xq_m" to semester
        )
        return JwParams(Coin, HttpMethod.POST, params, charset("utf-8"))
    }

    /**
     * 能否重修某一门课的参数构建
     * @param userCode: 学号
     * @param classCode: 课程代码
     */
    fun canRetake(userCode: String, classCode: String): JwParams {
        val params = listOf(
            "xh" to userCode,
            "kcdm" to classCode
        )
        return JwParams(RepeatCourse, params = params, charset = charset("utf-8"))
    }

    /**
     * 选课参数
     */
    fun saveCourse(userCode: String, ec: ElectiveCourse, keyTime: KeyTimeParam): JwParams {
        val isBuyBook = if (ec.buy) "1" else "0"
        val isCx = if (ec.retake) "1" else "0"
        val isYxtj = if (ec.adjust) "1" else "0"
        val paramStr = "xktype=2" +
                "&xn=${ecConfig.year}" +
                "&xq=${ecConfig.semester}" +
                "&xh=$userCode" +
                "&kcdm=${ec.classCode}" +
                "&skbjdm=${ec.classNum}" +
                "&xkh=${ec.classNum}" +
                "&xk_points=${ec.coin}" +
                "&is_buy_book=$isBuyBook" +
                "&is_cx=$isCx" +
                "&is_yxtj=$isYxtj" +
                "&kclb1=02&kclb2=02"
        val params = Encrypt.getEncParam(paramStr, keyTime.time, keyTime.key)
        return JwParams(SaveCourse, HttpMethod.POST, params, charset("utf-8"))
    }

    /**
     * 检测是否可以选择某门课
     */
    fun confirmCanElective(userCode: String, classCode: String): JwParams {
        val params = listOf(
                "xh" to userCode,
                "xn" to ecConfig.year,
                "xq_m" to ecConfig.semester,
                "kcdm" to classCode
        )
        return JwParams(ConfirmCanElective, HttpMethod.POST, params, charset("utf-8"))
    }

    /**
     * 删除一门课
     */
    fun cancelCourse(userCode: String, classNum: String, classCode: String, keyTime: KeyTimeParam): JwParams {
        val paramStr = "xn=${ecConfig.year}" +
                "&xq=${ecConfig.semester}" +
                "&xh=$userCode" +
                "&kcdm=$classCode" +
                "&skbjdm=$classNum" +
                "&xktype=4"
        val params = Encrypt.getEncParam(paramStr, keyTime.time, keyTime.key)
        return JwParams(CancelCourse, HttpMethod.POST, params, charset("utf-8"))
    }

    /**
     * 获取毕业学分要求
     */
    fun requiredCredit(): JwParams{
        val params = listOf(
                "tableId" to "6033"
        )
        return JwParams(DataTable, HttpMethod.POST, params)
    }

    /**
     * 加密参数
     */
    fun keyTimeParam(): JwParams {
        return JwParams(KeyTimeParam)
    }

    /**
     * 获取成绩
     */
    fun score(userCode: String, keyTime: KeyTimeParam): JwParams {
        val param = "xn=${ecConfig.year}&xq=${ecConfig.semester}" +
                "&ysyx=yscj&sjxz=sjxz1&ysyxS=on&sjxzS=on&userCode=$userCode"
        val params = Encrypt.getEncParamStr(param, keyTime.time, keyTime.key)
        return JwParams("$Score?$params")
    }

    /**
     * 获取建议课表
     * @param userCode: 学号
     * @param year: 年级
     * @param specialtyNumber: 专业代码
     */
    fun planCourse(userCode: String, year: String, specialtyNumber: String): JwParams{
        val code = year.substring(2) + specialtyNumber + userCode.substring(userCode.length - 3)
        val params = listOf(
                "xh" to code,
                "tableId" to "2508"
        )
        return JwParams(DataTable, HttpMethod.POST, params)
    }
}


